package com.jsean.demo;

import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@Slf4j
public class LuceneDemo {
    // 索引存储路径
    private static String indexDir = "lucene-index";

    private static void getIndexDir() {
        Properties props = new Properties();
        try (InputStream is = LuceneDemo.class.getClassLoader().getResourceAsStream("application.properties")) {
            props.load(is);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        indexDir = props.getProperty("app.filter", "lucene-index");
    }

    public static void main(String[] args) {
        try {
            getIndexDir();

            // 1. 创建索引
            createIndex();

            // 2. 执行搜索
            search("content", "lucene");

            // 3. 执行短语搜索
            searchPhrase("content", "apache lucene");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建索引
     */
    private static void createIndex() throws IOException {
        // 使用标准分析器
        Analyzer analyzer = new StandardAnalyzer();

        // 创建内存索引目录（实际项目中可以用FSDirectory）
        Directory directory = FSDirectory.open(Paths.get(indexDir));

        // 索引配置
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);

        // 创建索引写入器
        try (IndexWriter writer = new IndexWriter(directory, config)) {
            // 创建一些文档
            List<Document> documents = new ArrayList<>();

            // 文档1
            Document doc1 = new Document();
            doc1.add(new StringField("id", "1", Field.Store.YES));
            doc1.add(new TextField("title", "Introduction to Lucene", Field.Store.YES));
            doc1.add(new TextField("content", "Apache Lucene is a high-performance, full-featured text search engine library.", Field.Store.YES));
            documents.add(doc1);

            // 文档2
            Document doc2 = new Document();
            doc2.add(new StringField("id", "2", Field.Store.YES));
            doc2.add(new TextField("title", "Advanced Lucene", Field.Store.YES));
            doc2.add(new TextField("content", "Learn how to use Lucene for advanced search features.", Field.Store.YES));
            documents.add(doc2);

            // 文档3
            Document doc3 = new Document();
            doc3.add(new StringField("id", "3", Field.Store.YES));
            doc3.add(new TextField("title", "Lucene vs Elasticsearch", Field.Store.YES));
            doc3.add(new TextField("content", "Comparison between Lucene and Elasticsearch search capabilities.", Field.Store.YES));
            documents.add(doc3);

            // 添加文档到索引
            writer.addDocuments(documents);

            // 提交更改
            writer.commit();

            // 由于 numDocs() 方法在 IndexWriter 中未定义，我们可以通过创建 IndexReader 来获取文档数量
            try (IndexReader reader = DirectoryReader.open(writer)) {
                System.out.println("索引创建完成，共索引 " + reader.numDocs() + " 个文档");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 执行搜索
     * @param field 搜索字段
     * @param queryText 查询文本
     */
    private static void search(String field, String queryText) throws IOException {
        // 打开索引目录
        Directory directory = FSDirectory.open(Paths.get(indexDir));

        // 创建索引读取器
        try (IndexReader reader = DirectoryReader.open(directory)) {
            // 创建索引搜索器
            IndexSearcher searcher = new IndexSearcher(reader);

            // 创建查询解析器
            Analyzer analyzer = new StandardAnalyzer();
            QueryParser parser = new QueryParser(field, analyzer);

            // 解析查询字符串
            Query query = parser.parse(queryText);

            // 执行搜索，获取前10个结果
            TopDocs results = searcher.search(query, 10);
            System.out.println("\n搜索 '" + queryText + "' 找到 " + results.totalHits.value + " 个结果:");

            // 打印结果
            for (ScoreDoc scoreDoc : results.scoreDocs) {
                Document doc = searcher.doc(scoreDoc.doc);
                System.out.println(String.format(
                        "ID: %s, 标题: %s, 得分: %.2f",
                        doc.get("id"),
                        doc.get("title"),
                        scoreDoc.score
                ));
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行短语搜索
     * @param field 搜索字段
     * @param phrase 短语
     */
    private static void searchPhrase(String field, String phrase) throws IOException {
        // 打开索引目录
        Directory directory = FSDirectory.open(Paths.get(indexDir));

        // 创建索引读取器
        try (IndexReader reader = DirectoryReader.open(directory)) {
            // 创建索引搜索器
            IndexSearcher searcher = new IndexSearcher(reader);

            // 创建短语查询
            PhraseQuery query = new PhraseQuery(field, phrase.split(" "));

            // 执行搜索
            TopDocs results = searcher.search(query, 10);
            System.out.println("\n短语搜索 '" + phrase + "' 找到 " + results.totalHits.value + " 个结果:");

            // 打印结果
            for (ScoreDoc scoreDoc : results.scoreDocs) {
                Document doc = searcher.doc(scoreDoc.doc);
                System.out.println(String.format(
                        "ID: %s, 标题: %s, 内容: %s",
                        doc.get("id"),
                        doc.get("title"),
                        doc.get("content")
                ));
            }
        }
    }
}